extends Node

# This clas contains useful methods used accross the project

# emitted when data is successfully loaded from a file 
signal data_loaded(key,value)

const IS_DEBUG : bool = true
const DESKTOP_OS  : Array = ["Windows","OSX" , "X11"]


onready var _thread : Thread  = B4DFramework.main_thread



# Print a debug line 
static func debug(caller : String , type : int , message : String = ""):
	if not IS_DEBUG:
		return
	if type == 1: # normal message
		print( caller, " DEBUG MESSAGE : ", message)
	else: # 0 error 
		printerr(caller + " DEBUG ERROR : " + message )


# Save data to a file in user path 
# Using a thread to make the call in bg
func save_to_file_async(key : String , value : Dictionary):
	var thread_data := {
		"key" : key,
		"value" : value,
	}
	
	var err 
	while true: # Wait for the thread to be free to use
		err = _thread.start(self,"_save_to_file",thread_data)
		if err == OK:
			break
		yield(get_tree().create_timer(0.5),"timeout")
	
	if err != OK:
		debug("save_to_file_async",1,"THREAD ERROR")


# Read data from file saved in user path 
# Using a thread to make the call in bg
# To get data a @signal must be connected to (data_loaded)
func read_from_file_async(key : String):
	
	var err 
	while true: # wait for the thread to be free
		err = _thread.start(self,"_read_from_file",key)
		if err == OK:
			break
		yield(get_tree().create_timer(0.5),"timeout")
		
	if err != OK:
		debug("read_from_file_async",1,str(err))


func add_admob_manifest(app_id : String) -> void:
	
	if not DESKTOP_OS.has(OS.get_name()):
		return

	var admob_meta := "<!-- admob app-id -->\n<meta-data\nandroid:name=\"com.google.android.gms.ads.APPLICATION_ID\"\nandroid:value=\"" + app_id + "\"/>"
	
	var manifest_path : String = ProjectSettings.globalize_path("res://") + "android/build/AndroidManifest.xml"
	
	var file : File = File.new()
	
	if file.file_exists(manifest_path):
		file.open(manifest_path,File.READ_WRITE)
	else:
		debug("add_admob_manifest",0,"Check Exporting to Android in documentation")
		return
	
	var manifest_txt : String = file.get_as_text()
	var manifest_lines : PoolStringArray = manifest_txt.xml_escape().split("\n")
	
	var index = 0 
	for line in manifest_lines:
		if line == "&lt;!-- admob app-id --&gt;":
			debug("add_admob_manifest",1,"Already exists")
			file.close()
			return
		if line == "&lt;!-- Custom application XML added by add-ons. --&gt;":
			manifest_lines.set(index,admob_meta + "\n" + line)
		index += 1
	
	manifest_txt = manifest_lines.join("\n")
	
	file.store_string(manifest_txt.xml_unescape())
	file.close()


func add_multidex() -> void:
	if not DESKTOP_OS.has(OS.get_name()):
		return

	var multidex_dependency := "//multidex\nimplementation \"androidx.multidex:multidex:2.0.1\""
	var multidex_config := "multiDexEnabled true"
	
	var gradle_path : String = ProjectSettings.globalize_path("res://") + "android/build/build.gradle"
	
	var file : File = File.new()
	
	if file.file_exists(gradle_path):
		file.open(gradle_path,File.READ_WRITE)
	else:
		debug("add_multidex",0,"Check Exporting to Android in documentation")
		return
	
	var gradle_txt : String = file.get_as_text()
	var gradle_lines : PoolStringArray = gradle_txt.xml_escape().split("\n")
	
	var index = 0 
	for line in gradle_lines:
		if line == "//multidex":
			debug("add_multidex",1,"Already exists")
			file.close()
			return
		if line == "//CHUNK_DEPENDENCIES_BEGIN":
			gradle_lines.set(index,multidex_dependency + "\n" + line)
		if line == "//CHUNK_ANDROID_DEFAULTCONFIG_BEGIN":
			gradle_lines.set(index,multidex_config + "\n" + line)
		index += 1
	
	gradle_txt = gradle_lines.join("\n")
	
	file.store_string(gradle_txt.xml_unescape())
	file.close()

func _save_to_file(data : Dictionary) -> void:
	var key : String = data.key
	var value : Dictionary = data.value
	
	var file := File.new()
	var file_path := "user://" + key + ".json"
	var json_data := JSON.print(value , "\t")
	
	file.open(file_path,File.WRITE)
	file.store_string(json_data)
	file.close()
	call_deferred("_save_to_file_deferred")



func _read_from_file(key : String) -> Dictionary:
	var file := File.new()
	var file_path := "user://" + key + ".json"
	
	if file.file_exists(file_path):
		
		file.open(file_path,File.READ)
		var file_str := file.get_as_text()
		file.close()
		
		call_deferred("_read_from_file_deferred")
		
		var result : Dictionary = JSON.parse(file_str).result
		debug("_read_from_file",1, str(result))
		
		B4DFramework.is_new_user = false
		return result
	else: # New user or deleted data files (create new ones)
		B4DFramework.is_new_user = true
	
		debug("_read_from_file",0, "NEW USER CREATING NEW DATA FILES")
		match key:
			"score" :
				save_to_file_async(key,UserData.get_score())
			"skins" :
				save_to_file_async(key,UserData.get_skins())
			"settings" :
				save_to_file_async(key,UserData.get_settings())
		call_deferred("_read_from_file_deferred")
		return {}


func _save_to_file_deferred():
	_thread.wait_to_finish()


func _read_from_file_deferred():
	var data : Dictionary = _thread.wait_to_finish()
	if data.size() > 0:
		emit_signal("data_loaded",data.key , data)

